﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SQLite;

namespace Ruandao.MiniAccess.Sqlite
{
	/// <summary>
	/// 利用了Sqlite DLL中提供的功能，从数据库中得到表的架构。
	/// </summary>
	public class TableSchema
	{
		private SQLiteConnection conn = null;

		/// <summary>
		/// 表名
		/// </summary>
		private string tableName;
		/// <summary>
		/// 所有的列信息
		/// </summary>
		private IList<ColumnSchema> columns = new List<ColumnSchema>();
		private IList<string> primaryKeyColumns = new List<string>();
		private IList<string> foreignKeyColumns = new List<string>();
		private string identityColumn = "";

		/// <summary>
		/// 获取指定数据库中的表的架构，以此来构造实例。
		/// <br/>异常：ArgumentNullException(任一个参数为null),ArgumentException(无效的表名),
		/// NotSupportedException(表中有不止一个的标识列)
		/// </summary>
		/// <param name="tableName">表名。</param>
		/// <param name="database">数据库对象。</param>
		public TableSchema(string tableName, DataTable database)
		{
			if (database == null || tableName == null)
				throw new ArgumentNullException("获取数据表的架构，必须指定有效的数据库对象和表名称。", "database, tableName");

			this.tableName = tableName;
			GetColumnInfo(tableName, database);//获得所有列信息
		}
		/// <summary>
		/// 获取表名。
		/// </summary>
		public String TableName
		{
			get { return tableName; }
		}

		/// <summary>
		/// 获取表中的所有字段信息。
		/// </summary>
		public IList<ColumnSchema> Columns
		{
			get { return columns; }
		}

		/// <summary>
		/// 获取表中所有主键的字段信息。
		/// </summary>
		public IList<ColumnSchema> PrimaryKeyColumns
		{
			get
			{
				IList<ColumnSchema> cols = new List<ColumnSchema>();
				foreach (ColumnSchema col in columns)
				{
					if (IsPrimaryKey(col.ColumnName))
					{
						cols.Add(col);
					}
				}
				return cols;
			}
		}

		/// <summary>
		/// 获取表中所有主键的字段信息。
		/// </summary>
		public IList<ColumnSchema> ForeignKeyColumns
		{
			get
			{
				IList<ColumnSchema> cols = new List<ColumnSchema>();
				foreach (ColumnSchema col in columns)
				{
					if (IsForeignKey(col.ColumnName))
					{
						cols.Add(col);
					}
				}
				return cols;
			}
		}

		/// <summary>
		/// 获取表中的标识列的名称。如果没有标识列则返回""。如果有不只一个标识列，则抛出异常。
		/// </summary>
		public string IdentityColumn
		{
			get { return identityColumn; }
		}

		/// <summary>
		/// 判断制定的字段是否为标识列。
		/// </summary>
		/// <param name="columnName">字段名。</param>
		/// <returns>返回true,表示指定列是标识列，否则，指定列不是标识列。</returns>
		public bool IsIdentity(string columnName)
		{
			return (identityColumn == columnName) ? true : false;
		}

		/// <summary>
		/// 判断指定列是否是主键字段。
		/// </summary>
		/// <param name="columnName">字段名。</param>
		/// <returns>返回true,表示指定列是主键字段，否则，指定列不是主键字段。</returns>
		public bool IsPrimaryKey(string columnName)
		{
			return primaryKeyColumns.Contains(columnName);
		}

		/// <summary>
		/// 判断制定列是否是外键。
		/// </summary>
		/// <param name="columnName">字段名。</param>
		/// <returns>返回true,表示指定列是外键字段，否则，指定列不是外键字段。</returns>
		public bool IsForeignKey(string columnName)
		{
			return foreignKeyColumns.Contains(columnName);
		}

		/// <summary>
		/// 获取指定列的架构。
		/// </summary>
		/// <param name="columnName"></param>
		/// <returns>如果表中没有指定名称的列，则返回null。</returns>
		public ColumnSchema GetColumn(string columnName)
		{
			foreach (ColumnSchema col in this.columns)
			{
				if (col.ColumnName.ToLower() == columnName.ToLower())
				{
					return col;
				}
			}
			return null;
		}

		#region 私有工具函数
		private void GetColumnInfo(string tableName, DataTable database)
		{
			DataTable table = database;
			foreach (DataRow item in table.Rows)
			{//每一行是一列的信息

				columns.Add(new ColumnSchema(
					item["column_name"].ToString()
					, (Boolean)item["Primary_Key"]
					, item["data_type"].ToString()
					, (int)item["character_maximum_length"]
					, (Boolean)item["is_Nullable"]
					));

				if (Convert.ToBoolean(item["PRIMARY_KEY"]) == true)
				{//当前列是否为主键，若是，则增加到primaryKeyColumns集合
					primaryKeyColumns.Add(item["COLUMN_NAME"].ToString());
					identityColumn = item["COLUMN_NAME"].ToString();
				}
			}
		}
		#endregion
	}

}